package com.xiashitech.agent.db.dao.extload;

import cn.hutool.core.util.HashUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.db.Db;
import cn.hutool.db.Entity;
import com.xiashitech.agent.cache.authquery.extloadproxy.DataWaterMarkConfigLFUCacheProxy;
import com.xiashitech.agent.db.entity.DataWaterMarkConfig;
import com.xiashitech.agent.db.extload.LocalDataSource;
import com.xiashitech.agent.utils.XSUtil;

import java.sql.SQLException;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 数据水印配置表DAO
 *
 * @author guoxiaoyong@xs.com
 * 2023-12-04 7:02 AM
 **/
public class DataWaterMarkConfigDao {

    public void saveInitData(List<DataWaterMarkConfig> dataWaterMarkConfigList) {
        for (DataWaterMarkConfig dataWaterMarkConfig : dataWaterMarkConfigList) {
            try {
                Entity entity = Entity.create(DataWaterMarkConfig.TABLE_NAME).parseBean(dataWaterMarkConfig, true, true);
                Db.use(LocalDataSource.getDS()).insert(entity);
            } catch (RuntimeException | SQLException e) {
                XSUtil.debug("Insert ERROR {}", e.getMessage());
            }
        }
    }

    /**
     * 水印配置变更
     *
     * @param dataWaterMarkConfigList
     */
    public void saveChangeData(List<DataWaterMarkConfig> dataWaterMarkConfigList) {
        try {
            deleteByChangeList(dataWaterMarkConfigList);
            for (DataWaterMarkConfig up : dataWaterMarkConfigList) {
                Entity entity = Entity.create(DataWaterMarkConfig.TABLE_NAME).parseBean(up, true, true);
                // 指定唯一约束键后可进行merge操作(insert/update)
                Db.use(LocalDataSource.getDS()).upsert(entity, "id");
                DataWaterMarkConfigLFUCacheProxy.add(cacheKey(up.getAppName(), up.getApiPath()), up);
            }
        } catch (SQLException e) {
            XSUtil.debug("saveChangeData ERROR {}", e.getMessage());
        }
    }

    public void truncate() throws SQLException {
        Db.use(LocalDataSource.getDS()).execute("TRUNCATE TABLE " + DataWaterMarkConfig.TABLE_NAME);
    }

    /**
     * 根据APPName + apiPath查询水印配置信息
     *
     * @param appName
     * @param apiPath
     * @return
     * @throws SQLException
     */
    public DataWaterMarkConfig find(String appName, String apiPath) throws SQLException {
        List<DataWaterMarkConfig> dataWaterMarkConfigList;
        String cacheKey = cacheKey(appName, apiPath);
        // Cache Get（考虑缓存穿透场景）
        if (DataWaterMarkConfigLFUCacheProxy.hasKey(cacheKey)) {
            return DataWaterMarkConfigLFUCacheProxy.get(cacheKey);
        }
        String sql = "SELECT * FROM " + DataWaterMarkConfig.TABLE_NAME + " WHERE APP_NAME = ? AND API_PATH = ?";
        dataWaterMarkConfigList = Db.use(LocalDataSource.getDS()).query(sql, DataWaterMarkConfig.class, appName, apiPath);
        if (dataWaterMarkConfigList != null && !dataWaterMarkConfigList.isEmpty()) {
            // Cache Put
            DataWaterMarkConfigLFUCacheProxy.add(cacheKey, dataWaterMarkConfigList.get(0));
            return dataWaterMarkConfigList.get(0);
        }
        return null;
    }

    private static String cacheKey(String appName, String apiPath) {
        String cacheKey = StrUtil.format("{}:{}:{}", DataWaterMarkConfig.TABLE_NAME, appName, apiPath);
        return String.valueOf(HashUtil.apHash(cacheKey));
    }

    /**
     * 将数据库中不包含此次更新的数据ID对应的数据全删除
     * @param changeList
     * @throws SQLException
     */
    private static void deleteByChangeList(List<DataWaterMarkConfig> changeList) throws SQLException {
        List<Entity> entityList = Db.use(LocalDataSource.getDS()).findAll(DataWaterMarkConfig.TABLE_NAME);
        List<Long> changeIds = changeList.stream().map(DataWaterMarkConfig::getId).collect(Collectors.toList());
        entityList.stream().mapToLong(entity -> entity.getLong("id"))
                .filter(id -> !changeIds.contains(id))
                .forEach(id -> {
                    try {
                        Entity entity = Db.use(LocalDataSource.getDS()).get(Entity.create(DataWaterMarkConfig.TABLE_NAME).set("id", id));
                        Db.use(LocalDataSource.getDS()).del(DataWaterMarkConfig.TABLE_NAME, "id", id);
                        DataWaterMarkConfigLFUCacheProxy.remove(cacheKey(entity.getStr("appName"), entity.getStr("apiPath")));
                        XSUtil.debug(DataWaterMarkConfigDao.class, "saveChangeData delete data id: {}", id);
                    } catch (SQLException e) {
                        throw new RuntimeException(e);
                    }
                });
    }

    public long count() {
        long cnt = -1;
        try {
            cnt = Db.use(LocalDataSource.getDS()).count(Entity.create(DataWaterMarkConfig.TABLE_NAME));
        } catch (SQLException e) {
            XSUtil.debug("Insert ERROR {}", e.getMessage());
        }
        return cnt;
    }
}
